package com.toilet.easyvideofx.compent;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.toilet.easyvideofx.api.response.*;
import com.toilet.easyvideofx.global.GlobalCache;
import com.toilet.easyvideofx.global.HttpStatus;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 请求组件 todo 后续需要做统一异常响应
 */
public class RequestComponent {
    /**
     * 公共请求头
     */
    private static final ConcurrentHashMap<String, String> commonHeader;
    private static final Gson gson = new Gson();

    static {
        commonHeader = new ConcurrentHashMap<>();
        commonHeader.put("Content-Type", "application/json");
        commonHeader.put("Accept", "application/json");
    }

    /**
     * 设置额外的公共请求头
     */
    public static void putExtraHeader(String key, String value) {
        if (key == null || value == null) {
            return;
        }
        commonHeader.put(key, value);
    }

    /**
     * 发送post请求
     *
     * @param body  请求体
     * @param url   请求地址
     * @param clazz 响应体
     * @return
     */
    public static <T> T post(Object body, String url, Class<T> clazz) {
        HttpClient client = HttpClient.newHttpClient();
        String requestUrl = GlobalCache.getBaseUrl() + url;
        System.out.println("请求url :" + requestUrl);

        // 创建HttpRequest对象
        HttpRequest.Builder builder = HttpRequest.newBuilder()
                .uri(URI.create(requestUrl));
        // 构建入通用请求头
        commonHeader.forEach(builder::header);
        // 创建请求体
        String requestBody = gson.toJson(body);


        HttpRequest request = builder
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .build();
        HttpResponse<String> response;
        try {
            response = client.send(request, HttpResponse.BodyHandlers.ofString());
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
        // 获取响应体
        String responseBody = response.body();
        Type type = TypeToken.getParameterized(BaseResponse.class, clazz).getType();
        BaseResponse<T> baseResponse = gson.fromJson(responseBody, type);
        if (baseResponse.getCode() != HttpStatus.SUCCESS) {
            throw new RuntimeException("异常");
        }
        return baseResponse.getData();
    }

    /**
     * 发送get请求
     *
     * @param url    请求地址
     * @param clazz  响应体
     * @param params 请求参数
     * @return
     */
    public static <T> T get(String url, Class<T> clazz, Map<String, String> params) {
        HttpClient client = HttpClient.newHttpClient();
        String requestUrl = appendRequestUrl(params, GlobalCache.getBaseUrl() + url);
//        System.out.println("请求url :" + requestUrl);
        // 构建入通用请求头
        HttpRequest.Builder builder = HttpRequest.newBuilder()
                .uri(URI.create(requestUrl));
        commonHeader.forEach(builder::header);
        // 创建请求体
        HttpRequest request = builder.GET().build();
        HttpResponse<String> response;
        try {
            response = client.send(request, HttpResponse.BodyHandlers.ofString());
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
        // 获取响应体
        String responseBody = response.body();
        Type type = TypeToken.getParameterized(BaseResponse.class, clazz).getType();
        BaseResponse<T> baseResponse = gson.fromJson(responseBody, type);
        if (baseResponse.getCode() != HttpStatus.SUCCESS) {
            throw new RuntimeException("异常");
        }
        return baseResponse.getData();
    }

    /**
     * 发送分页get请求
     *
     * @param url    请求地址
     * @param type   响应体
     * @param params 请求参数
     * @return
     */
    public static <T> BasePageResponse<T> getPage(String url, Type type, Map<String, String> params) {
        HttpClient client = HttpClient.newHttpClient();
        String requestUrl = appendRequestUrl(params, GlobalCache.getBaseUrl() + url);
        System.out.println("请求url :" + requestUrl);
        // 构建入通用请求头
        HttpRequest.Builder builder = HttpRequest.newBuilder()
                .uri(URI.create(requestUrl));
        commonHeader.forEach(builder::header);
        // 创建请求体
        HttpRequest request = builder.GET().build();
        HttpResponse<String> response;
        try {
            response = client.send(request, HttpResponse.BodyHandlers.ofString());
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
        // 获取响应体
        String responseBody = response.body();
        BaseResponse<BasePageResponse<T>> baseResponse = gson.fromJson(responseBody, type);
        if (baseResponse.getCode() != HttpStatus.SUCCESS) {
            throw new RuntimeException("异常");
        }
        System.out.println(baseResponse.getData());
        return baseResponse.getData();
    }

    /**
     * 发送get下载请求,直接获取所有字节数组
     *
     * @param body 请求体
     * @param url  请求地址
     * @return 返回字节数组
     */
    public static FileResponse download(Object body, String url) {
        HttpClient client = HttpClient.newHttpClient();
        String requestUrl = GlobalCache.getBaseUrl() + url;
        System.out.println("请求url :" + requestUrl);
        // 创建HttpRequest对象
        HttpRequest.Builder builder = HttpRequest.newBuilder()
                .uri(URI.create(requestUrl));
        commonHeader.forEach(builder::header);
        HttpRequest httpRequest = builder.GET().build();
        try {
            HttpResponse<InputStream> response = client.send(httpRequest, HttpResponse.BodyHandlers.ofInputStream());
            if (response.statusCode() == HttpStatus.SUCCESS) {
                InputStream stream = response.body();
                byte[] bytes = stream.readAllBytes();
                stream.close();
                Map<String, List<String>> map = response.headers().map();
                List<String> strings = map.get("Content-Disposition");
                String[] split = strings.get(0).split(";");
                String fileName = split[1].substring("filename=".length());
                FileResponse fileResponse = new FileResponse(bytes, fileName);
                System.out.println(strings);
                return fileResponse;
            }
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }

        return null;
    }

    /**
     * 发送get下载请求,直接获取流
     *
     * @param params 请求参数
     * @param url    请求地址
     * @return 返回字节数组
     */
    public static FileStreamResponse downloadStream(Map<String, String> params, String url) {
        HttpClient client = HttpClient.newHttpClient();
        String requestUrl = appendRequestUrl(params, GlobalCache.getBaseUrl() + url);
        System.out.println("请求url :" + requestUrl);
        // 创建HttpRequest对象
        HttpRequest.Builder builder = HttpRequest.newBuilder()
                .uri(URI.create(requestUrl));
        HttpRequest httpRequest = builder.GET().build();
        commonHeader.forEach(builder::header);
        try {
            HttpResponse<InputStream> response = client.send(httpRequest, HttpResponse.BodyHandlers.ofInputStream());
            if (response.statusCode() == HttpStatus.SUCCESS) {
                InputStream stream = response.body();
                Map<String, List<String>> map = response.headers().map();
                List<String> strings = map.get("Content-Disposition");
                List<String> length = map.get("Content-Length");
                Long fileSize = Long.valueOf(length.get(0));
                String[] split = strings.get(0).split(";");
                String fileName = split[1].substring("filename=".length());
                FileStreamResponse fileResponse = new FileStreamResponse(stream, fileName, fileSize);
                System.out.println(strings);
                return fileResponse;
            }
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    /**
     * 发送get下载请求,直接获取流
     *
     * @param params 请求参数
     * @param url    请求地址
     * @return 返回字节数组
     */
    public static BaseResponse<FileUploadResponse> uploadStream(Map<String, String> params, byte[] buffer, String url) {

        HttpClient client = HttpClient.newHttpClient();
        String requestUrl = appendRequestUrl(params, GlobalCache.getBaseUrl() + url);

        System.out.println("请求url :" + requestUrl);

        try {
            // 创建一个HttpRequest对象
            HttpRequest.Builder builder = HttpRequest.newBuilder()
                    .uri(URI.create(requestUrl))
                    .header("Content-Type", "application/octet-stream")
                    .POST(HttpRequest.BodyPublishers.ofByteArray(buffer));

            commonHeader.forEach(builder::header);
            HttpResponse<String> response = client.send(builder.build(), HttpResponse.BodyHandlers.ofString());
            if (response.statusCode() == HttpStatus.SUCCESS) {
                // 获取响应体
                String responseBody = response.body();
                Type type = TypeToken.getParameterized(BaseResponse.class, FileUploadResponse.class).getType();
                return gson.fromJson(responseBody, type);
            }
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    /**
     * 拼接带请求参数的url
     *
     * @param params
     * @param url
     * @return
     */
    private static String appendRequestUrl(Map<String, String> params, String url) {
        if (params == null || params.isEmpty()) {
            return url;
        }
        boolean isFirst = true;
        StringBuilder requestUrl = new StringBuilder(url);
        for (String paramName : params.keySet()) {
            requestUrl.append(isFirst ? "?" : "&")
                    .append(URLEncoder.encode(paramName, StandardCharsets.UTF_8))
                    .append("=")
                    .append(URLEncoder.encode(params.get(paramName), StandardCharsets.UTF_8));
            isFirst = false;
        }
        return requestUrl.toString();
    }
}
